package cube

import (
	"database/sql"
	"fmt"
	"shqsoft.cn/pasnj/base"
	"shqsoft.cn/pasnj/bi/database"
	"shqsoft.cn/pasnj/bi/datapackage"
	"strings"

	"github.com/go-redis/redis"
	log "github.com/sirupsen/logrus"
)

//Relation 关系表
type Relation struct {
	setting  *datapackage.Relation
	redisCli *redis.Client
	month    string
	lkeys    map[int]string
	skeys    map[int]string
}

//getRelation 新建关系表
func getRelation(setting *datapackage.Relation, month string) (rela *Relation) {
	rela = &Relation{
		setting:  setting,
		redisCli: base.RedisClients[setting.RedisIndex],
		month:    month,
	}
	lkeys := make(map[int]string)
	skeys := make(map[int]string)
	for i, item := range setting.Items {
		lkeys[i], skeys[i] = rela.getRedisKey(&item)
	}
	rela.lkeys = lkeys
	rela.skeys = skeys
	return
}
func (r *Relation) build() (err error) {
	dl := database.DefaultDataLoader
	log.Infof("开始构建关系表:%s,月份:%s....", r.setting.Table.Name, r.month)
	var rows *sql.Rows
	if r.setting.Table.Type == "proc" {
		rows, err = dl.LoadDataByProc(r.setting.Table.Name, r.month)
	} else {
		rows, err = dl.LoadDataBySQL(fmt.Sprintf("select * from %s", r.setting.Table.Name))
	}
	if err != nil {
		return
	}
	defer rows.Close()
	if err := r.delete(); err != nil {
		return err
	}
	cols, err := base.GetColumns(rows)
	if err != nil {
		return err
	}
	clen := len(cols)
	values := make([]sql.NullString, clen)
	scanArgs := make([]interface{}, clen)
	for i := 0; i < clen; i++ {
		scanArgs[i] = &values[i]
	}
	for rows.Next() {
		err := rows.Scan(scanArgs...)
		if err != nil {
			return err
		}
		if err := r.addData(base.ToMap(cols, values)); err != nil {
			return err
		}
	}
	log.Infof("构建关系表:%s,月份:%s完成！", r.setting.Table.Name, r.month)
	return nil
}
func (r *Relation) addData(data map[string]interface{}) error {
	if r.setting.Table.PrimaryKey == "" {
		return fmt.Errorf("必须为关系%s表%s指定主键", r.setting.Name, r.setting.Table.Name)
	}
	keyVal := data[r.setting.Table.PrimaryKey]
	for i, item := range r.setting.Items {
		itemVal, ok := data[item.NameColumn]
		if !ok {
			return fmt.Errorf("表%s给定的数据中不存在字段%s", r.setting.Table.Name, item.NameColumn)
		}
		hkey := r.skeys[i] + base.ToString(itemVal)
		find := r.redisCli.Exists(hkey).Val()
		if find == 0 {
			if err := r.redisCli.RPush(r.lkeys[i], itemVal).Err(); err != nil {
				return fmt.Errorf("加载数据到关系%s表%s时出错:%s", r.setting.Name, r.setting.Table.Name, err)
			}
		}
		if err := r.redisCli.SAdd(hkey, keyVal).Err(); err != nil {
			return fmt.Errorf("加载数据到关系%s表%s时出错:%s", r.setting.Name, r.setting.Table.Name, err)
		}
	}
	return nil
}
func (r *Relation) getKeys(field string, vals ...string) ([]string, error) {
	for _, item := range r.setting.Items {
		if item.Name == field {
			for i := 0; i < len(vals); i++ {
				vals[i] = r.skeys[i] + vals[i]
			}
			break
		}
	}
	return vals, nil
}
func (r *Relation) getRedisKey(item *datapackage.RelationItem) (lkey string, skey string) {
	var suffix string
	if item.Period == "month" {
		suffix = r.month
	} else if item.Period == "year" {
		suffix = string(([]byte(r.month))[:4])
	}
	lkey = r.setting.Name + "." + item.Name
	skey = lkey + ":"
	if suffix != "" {
		lkey += ":" + suffix
		skey += suffix + ":"
	}
	return
}
func getRelationSetKey(name string, month string, key string) string {
	dp := datapackage.DefaultDP
	relaItem := strings.Split(name, ".")
	for _, rela := range dp.Relations {
		if relaItem[0] == rela.Name {
			for _, item := range rela.Items {
				if item.Name == relaItem[1] {
					var suffix string
					if item.Period == "month" {
						suffix = month
					}
					skey := name + ":"
					if suffix != "" {
						skey += suffix + ":"
					}
					return skey + key
				}
				break
			}
			break
		}
	}
	return ""
}

//delete 清除Index缓存
func (r *Relation) delete() error {
	for i := range r.setting.Items {
		if err := deleteByList(r.redisCli, r.skeys[i], r.lkeys[i]); err != nil {
			return err
		}
		if err := r.redisCli.Del(r.lkeys[i]).Err(); err != nil {
			return err
		}
	}
	return nil
}
